package com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSONObject;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.CallbackThirdPlatformAfterTaskCreatedService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.ThirdPlatformCallbackResolver;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.HttpUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.SpringUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.common.TaskCreatedEventMsg;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.NoticeTypeEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowParticipantInfoVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowReNodeAuthVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.ParticipantVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.log.FlowCommonOperateLogVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.notice.FlowNoticeTemplateInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowCommonOperateLogRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowNoticeTemplateRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowParticipantRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowReNodeAuthRepository;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.ManagementService;
import org.flowable.engine.common.impl.interceptor.Command;
import org.flowable.engine.common.impl.interceptor.CommandContext;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.identitylink.service.IdentityLinkType;
import org.flowable.identitylink.service.impl.persistence.entity.IdentityLinkEntity;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author lilh
 * @date 2019-05-20 16:16
 */
@Service
public class CallbackThirdPlatformAfterTaskCreatedServiceImpl implements CallbackThirdPlatformAfterTaskCreatedService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private FlowParticipantRepository flowParticipantRepository;

    @Autowired
    private ThirdPlatformCallbackResolver urlResolver;

    @Autowired
    private ManagementService managementService;

    @Autowired
    private FlowCommonOperateLogRepository flowCommonOperateLogRepository;

    @Autowired
    private FlowReNodeAuthRepository nodeAuthService;

    @Autowired
    private FlowNoticeTemplateRepository noticeTemplateService;

    @Override
    public void handle(Task task) {
        if (!(task instanceof TaskEntity)) {
            logger.warn("不处理任务节点类型", task);
            return;
        }

        TaskEntity taskEntity = (TaskEntity) task;
        String url = urlResolver.resolveCallbackUrlByProcessInstanceId(taskEntity.getProcessInstanceId());
        if (StringUtils.isEmpty(url)) {
            logger.debug("没有配置url,不处理");
            return;
        }
        TaskCreatedEventMsg taskCreatedEventMsg = resolveTaskCreatedMsg(taskEntity);
        List<ParticipantVo> participants = resolveParticipants(taskEntity);
        sendMsg(taskCreatedEventMsg, participants, url);
        logger.debug("任务创建完成，任务id为：" + taskEntity.getId());

    }

    @Override
    public void handle(List<Task> tasks) {
        for (Task task : tasks) {
            handle(task);
        }
    }

    private void sendMsg(TaskCreatedEventMsg taskCreatedEventMsg, List<ParticipantVo> participants, String url) {
        List<TaskCreatedEventMsg> msgs = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(participants)) {
            for (ParticipantVo participant : participants) {
                TaskCreatedEventMsg tmp = new TaskCreatedEventMsg();
                BeanUtils.copyProperties(taskCreatedEventMsg, tmp);
                tmp.setParticipantId(participant.getParticipantId());
                tmp.setParticipantType(participant.getParticipantType());
                tmp.setParticipantName(participant.getParticipantName());
                msgs.add(tmp);
            }
        } else {
            //若没有配置参与人、办理人和候选组，则不传人员信息
            msgs.add(taskCreatedEventMsg);
        }

        //通过http请求发送数据到第三方平台
        for (TaskCreatedEventMsg msg : msgs) {
            logger.info("回调创建工单接口数据为：{}", JSONObject.toJSONString(msg));
            String result = HttpUtils.sendHttpPost(url, JSONObject.toJSONString(msg));
            msg.setResult(result);
            logger.info("回调创建工单接口返回结果：{}", result);
        }
        //将回调信息写入数据库
        logToDb(msgs);
    }

    private void logToDb(List<TaskCreatedEventMsg> msgs) {
        for (TaskCreatedEventMsg msg : msgs) {
            FlowCommonOperateLogVo log = new FlowCommonOperateLogVo();
            log.setProcessInstanceId(msg.getProcessInstanceId());
            log.setTaskName(msg.getTacheName());
            log.setType(msg.getCommandCode());
            log.setTaskId(msg.getWorkItemId());
            log.setActivityId(msg.getTacheCode());
            log.setContent(JSONObject.toJSONString(msg));
            log.setCreateTime(new Date());
            log.setUpdateTime(new Date());
            flowCommonOperateLogRepository.insertOperateLog(log);
        }
    }


    @Override
    public List<ParticipantVo> resolveParticipants(TaskEntity taskEntity) {
        List<ParticipantVo> participants = new ArrayList<>();
        if (Objects.nonNull(taskEntity.getAssignee())) {
            ParticipantVo item = new ParticipantVo();
            item.setParticipantId(taskEntity.getAssignee());
            //如果设置了办理人
            FlowParticipantInfoVo participant = flowParticipantRepository.findByParticipantId(taskEntity.getAssignee());
            if (Objects.nonNull(participant)) {
                item.setParticipantName(participant.getParticipantName());
                if (Arrays.asList("STA", "USR").contains(participant.getParticipantType())) {
                    item.setParticipantType("USR");
                } else {
                    item.setParticipantType(participant.getParticipantType());
                }
            }
            participants.add(item);
        } else {
            //未设置办理人，则查询候选人和候选组
            List<ParticipantVo> participantVos = managementService.executeCommand(new QueryCandidateCmd(taskEntity));
            participants.addAll(participantVos);
        }
        return participants;
    }


    @Override
    public TaskCreatedEventMsg resolveTaskCreatedMsg(TaskEntity taskEntity) {
        TaskCreatedEventMsg msg = new TaskCreatedEventMsg();
        msg.setProcessInstanceId(taskEntity.getProcessInstanceId());
        msg.setTacheCode(taskEntity.getTaskDefinitionKey());
        msg.setTacheName(taskEntity.getName());
        msg.setWorkItemId(taskEntity.getId());
        //获取流程节点权限列表
        List<FlowReNodeAuthVo> nodeAuthList = nodeAuthService.listNodeAuthByProcdefIdAndNodeCode(taskEntity.getProcessDefinitionId(), taskEntity.getTaskDefinitionKey());
        Map<String, String> authMap = nodeAuthList.stream().collect(Collectors.toMap(FlowReNodeAuthVo::getAuthName, FlowReNodeAuthVo::getAuthContent));
        msg.setNodeAuth(authMap);
        //获取催办模版
        List<FlowReNodeAuthVo> urgeAuth = nodeAuthList.stream().filter(nodeAuth ->
                "urge".equalsIgnoreCase(nodeAuth.getAuthName()) && nodeAuth.getAuthSwitch()).collect(Collectors.toList());
        if (urgeAuth != null && !urgeAuth.isEmpty()) {
            List<FlowNoticeTemplateInfo> flowNoticeTemplateInfos = noticeTemplateService.listNoticeTemplateInfo(NoticeTypeEnum.TASK_REMIND.getCode());
            if (flowNoticeTemplateInfos != null && !flowNoticeTemplateInfos.isEmpty()) {
                Map<String, String> templateMap = flowNoticeTemplateInfos.stream().collect(Collectors.toMap(FlowNoticeTemplateInfo::getType, FlowNoticeTemplateInfo::getContent));
                msg.setNoticeTemplate(templateMap);
            }
        }
        return msg;
    }


    static class QueryCandidateCmd implements Command<List<ParticipantVo>> {

        private TaskEntity taskEntity;

        QueryCandidateCmd(TaskEntity taskEntity) {
            this.taskEntity = taskEntity;
        }

        @Override
        public List<ParticipantVo> execute(CommandContext commandContext) {
            List<ParticipantVo> participants = new ArrayList<>();
            //1.候选组
            Set<IdentityLink> candidates = taskEntity.getCandidates();
            if (CollectionUtils.isNotEmpty(candidates)) {
                for (IdentityLink candidate : candidates) {
                    ParticipantVo item = new ParticipantVo();
                    if (StringUtils.isNotEmpty(candidate.getGroupId())) {
                        item.setParticipantId(candidate.getGroupId());
                    } else {
                        item.setParticipantId(candidate.getUserId());
                    }
                    FlowParticipantInfoVo participant = SpringUtils.getBean(FlowParticipantRepository.class).findByParticipantId(item.getParticipantId());
                    if (Objects.nonNull(participant)) {
                        item.setParticipantName(participant.getParticipantName());
                        if (Arrays.asList("STA", "USR").contains(participant.getParticipantType())) {
                            item.setParticipantType("USR");
                        } else {
                            item.setParticipantType(participant.getParticipantType());
                        }
                    }
                    participants.add(item);
                }
            }

            //2.参与人
            List<IdentityLinkEntity> identityLinks = taskEntity.getIdentityLinks();
            for (IdentityLinkEntity identityLink : identityLinks) {
                if (Objects.equals(identityLink.getType(), IdentityLinkType.PARTICIPANT)) {
                    ParticipantVo item = new ParticipantVo();
                    item.setParticipantId(identityLink.getUserId());
                    FlowParticipantInfoVo participant = SpringUtils.getBean(FlowParticipantRepository.class).findByParticipantId(item.getParticipantId());
                    if (Objects.nonNull(participant)) {
                        item.setParticipantName(participant.getParticipantName());
                        if (Arrays.asList("STA", "USR").contains(participant.getParticipantType())) {
                            item.setParticipantType("USR");
                        } else {
                            item.setParticipantType(participant.getParticipantType());
                        }
                    }
                    participants.add(item);
                }
            }
            return participants;
        }
    }
}
